package com.yuanfeng.commoms.util;

//import org.apache.commons.lang.StringUtils;


import com.yuanfeng.commoms.config.YFConfig;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.PostConstruct;
import java.util.Iterator;
import java.util.Set;

/**
 * 1.1 字符串取值时进行延时操作 Redis 工具类 Created by zharounze
 */
@Component
public class RedisUtil {

    // protected static ReentrantLock lockPool = new ReentrantLock();
    // protected static ReentrantLock lockJedis = new ReentrantLock();

    private static final Logger LOGGER = LoggerFactory.getLogger(RedisUtil.class);

    // 正式

    private static String IP;
    // Redis的端口号
    private static Integer PORT;
    private static String PASSWORD;
    private static String DATABASES;

    @Value("${spring.redis.host}")
    private String redishost;
    @Value("${spring.redis.port}")
    private Integer redisposrt;
    @Value("${spring.redis.password}")
    private String redisPassword;
    @Value("${spring.redis.database}")
    private String redisDatabase;

    public void getRedisInfo() {
        PORT = this.redisposrt;
        IP = this.redishost;
        PASSWORD = this.redisPassword;
		DATABASES = this.redisDatabase;
    }

    @PostConstruct
    public void getRedisposrt() {
        PORT = this.redisposrt;
    }
    @PostConstruct
    public void getRedisHost() {
        IP = this.redishost;
    }
    @PostConstruct
    public void getRedisPassWord() {
        PASSWORD = this.redisPassword;
    }
    @PostConstruct
    public void getRedisDatabase() {
        DATABASES = this.redisDatabase;
    }

    // 可用连接实例的最大数目，默认值为8；
    // 如果赋值为-1，则表示不限制；如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)。
    private static final int MAX_ACTIVE = 1000;

    // 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例，默认值也是8。
    private static final int MAX_IDLE = 20;

    // 等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时。如果超过等待时间，则直接抛出JedisConnectionException；
    private static final int MAX_WAIT = -1;

    // 超时时间
    private static final int TIMEOUT = 3000;

    // 在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
    private static final boolean TEST_ON_BORROW = false;

    private static JedisPool jedisPool = null;

    /**
     * redis过期时间,以秒为单位
     */
    public final static int EXRP_FIVE_MIN = 5 * 60;
    // 一小时
    public final static int EXRP_HOUR = 60 * 60;
    // 一天
    public final static int EXRP_DAY = 60 * 60 * 24;
    // 一个月
    public final static int EXRP_MONTH = 60 * 60 * 24 * 30;

    /**
     * 初始化Redis连接池
     */
    private static void initialPool() {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(MAX_ACTIVE);
            config.setMaxIdle(MAX_IDLE);
            config.setMaxWaitMillis(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, IP, PORT, TIMEOUT,PASSWORD,Integer.valueOf(DATABASES));
        } catch (Exception e) {
            LOGGER.error("First create JedisPool error : " + e);
        }
    }

    /**
     * 在多线程环境同步初始化
     */
    private static synchronized void poolInit() {
        if (null == jedisPool) {
            initialPool();
        }
    }

    /**
     * 同步获取Jedis实例
     *
     * @return Jedis
     */
    public synchronized static Jedis getJedis() {

       /* System.out.println(IP);
        System.out.println(PASSWORD+"1");*/
        poolInit();
        Jedis jedis = null;
        try {
            if (null != jedisPool) {
                jedis = jedisPool.getResource();
                if(StringUtils.isNotBlank(PASSWORD)){
                    try {
                        jedis.auth(PASSWORD);
                    } catch (Exception e) {
                        LOGGER.error("Get jedis auth error : " + e);
                    }
                }
            }
        } catch (Exception e) {
            LOGGER.error("Get jedis error : " + e);
        }
        return jedis;
    }

    /**
     * 设置 String
     *
     * @param key
     * @param value
     */
    public synchronized static void set(String key, String value) {
        Jedis jedis = null;
        try {
            value = "".equals(value) ? "" : value;
            jedis = getJedis();
            jedis.set(key, value);
        } catch (Exception e) {
            LOGGER.error("key=" + key + "value=" + value);
            LOGGER.error("Set key error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * 设置 byte[]
     *
     * @param key
     * @param value
     */
    public synchronized static void set(byte[] key, byte[] value) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.set(key, value);
        } catch (Exception e) {
            LOGGER.error("key=" + key + "value=" + value);
            LOGGER.error("Set key error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * 设置 String 过期时间
     *
     * @param key
     * @param value
     * @param seconds 以秒为单位
     */
    public synchronized static void set(String key, String value, int seconds) {
        Jedis jedis = null;
        try {
            // value = !"".equals(value) ? "" : value;
            jedis = getJedis();
            jedis.setex(key, seconds, value);
        } catch (Exception e) {
            LOGGER.error("key=" + key + "value=" + value);
            LOGGER.error("Set keyex error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * 设置 byte[] 过期时间
     *
     * @param key
     * @param value
     * @param seconds 以秒为单位
     */
    public synchronized static void set(byte[] key, byte[] value, int seconds) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.set(key, value);
            jedis.expire(key, seconds);
        } catch (Exception e) {
            LOGGER.error("key=" + key + "value=" + value);
            LOGGER.error("Set key error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * 获取String值 ,如果不为null或者“”，就进行延时操作
     *
     * @param key
     * @return value
     */
    public synchronized static String get(String key) {
        Jedis jedis = null;
        String value = null;
        try {
            jedis = getJedis();
            if (null == jedis) {
                return null;
            }
            value = jedis.get(key);
            if (null != value && !"".equals(value)) {
                jedis.expire(key, YFConfig.TOKEN_OUTTIME);
            }
        } catch (Exception e) {
            LOGGER.error("key=" + key + "value=" + value);
            LOGGER.error(e.getMessage());
        } finally {
            closeRedis(jedis);
        }
        return value;
    }
    /**
     * 获取String值
     *
     * @param key
     * @return value
     */
    public synchronized static String getNoUpdateTime(String key) {
        Jedis jedis = null;
        String value = null;
        try {
            jedis = getJedis();
            if (null == jedis) {
                return null;
            }
            value = jedis.get(key);
        } catch (Exception e) {
            LOGGER.error("key=" + key + "value=" + value);
            LOGGER.error(e.getMessage());
        } finally {
            closeRedis(jedis);
        }
        return value;
    }
    public static String getRedis(String key) {
        Jedis jedis = getJedis();
        if (null == jedis) {
            return null;
        }
        String value = jedis.get(key);
        closeRedis(jedis);
        return value;
    }

    /**
     * @param key
     * @return value
     */
    public synchronized static String getNoExpire(String key) {
        Jedis jedis = getJedis();
        if (null == jedis) {
            return null;
        }
        String value = jedis.get(key);
        closeRedis(jedis);
        return value;
    }

    /**
     * 获取byte[]值
     *
     * @param key
     * @return value
     */
    public synchronized static byte[] get(byte[] key) {
        Jedis jedis = getJedis();
        if (null == jedis) {
            return null;
        }
        byte[] value = jedis.get(key);
        closeRedis(jedis);
        return value;
    }

    /**
     * 删除值
     *
     * @param key
     */
    public synchronized static void removeAll(String key) {
        try {
            Jedis jedis = getJedis();

            Iterator<String> it = jedis.keys(key + "*").iterator();
            while (it.hasNext()) {
                String key1 = it.next();
                // 清空缓存中记录的数据
                jedis.del(key1);
            }
            jedis.close();
        } catch (Exception e) {
            LOGGER.error("Remove keyex error : " + e);
        }
    }

    /**
     * 删除值
     *
     * @param key
     */
    public synchronized static void remove(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.del(key);
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("Remove keyex error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * 删除值
     *
     * @param key
     */
    public synchronized static void remove(byte[] key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.del(key);
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("Remove keyex error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * lpush
     *
     * @param key
     * @param key
     */
    public synchronized static void lpush(String key, String... strings) {
        Jedis jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            jedis.lpush(key, strings);
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("lpush error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * lpush
     *
     * @param key
     * @param key
     */
    public synchronized static void lpush(String key, Integer seconds, String... strings) {
        Jedis jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            jedis.lpush(key, strings);
            jedis.expire(key, seconds);
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("lpush error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * lrem
     *
     * @param key
     * @param count
     * @param value
     */
    public synchronized static void lrem(String key, long count, String value) {
        Jedis jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            jedis.lrem(key, count, value);
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("lpush error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * sadd
     *
     * @param key
     * @param value
     * @param seconds
     */
    public synchronized static void sadd(String key, String value, int seconds) {
        Jedis jedis = null;
        try {
            jedis = RedisUtil.getJedis();
            jedis.sadd(key, value);
            jedis.expire(key, seconds);
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("sadd error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * incr
     *
     * @param key
     * @return value
     */
    public synchronized static Long incr(String key) {
        Jedis jedis = getJedis();
        if (null == jedis) {
            return null;
        }
        long value = jedis.incr(key);
        closeRedis(jedis);
        return value;
    }

    /**
     * decr
     *
     * @param key
     * @return value
     */
    public synchronized static Long decr(String key) {
        Jedis jedis = getJedis();
        if (null == jedis) {
            return null;
        }
        long value = jedis.decr(key);
        closeRedis(jedis);
        return value;
    }

    /**
     * expire
     *
     * @param key,seconds
     * @return
     */
    public synchronized static void expire(String key, int seconds) {
        Jedis jedis = getJedis();
        try {
            jedis.expire(key, seconds);
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("Set keyex error : " + e);
        } finally {
            closeRedis(jedis);
        }
    }

    /**
     * exists
     *
     * @param key
     * @return
     */
    public static boolean exists(String key) {
        Jedis jedis = null;
        boolean value = false;
        try {
            jedis = getJedis();
            value = jedis.exists(key);

        } catch (Exception e) {
            LOGGER.error("Jedis-exists异常" + e.getMessage());
        } finally {
            closeRedis(jedis);
        }
        return value;
    }


    /**
     * 关闭jedis连接池
     *
     * @param jedis
     */
    public static void closeRedis(Jedis jedis) {
        if (jedis != null) {
            try {
                jedis.close();
            } catch (Exception e) {
                LOGGER.error("Jedis关闭异常" + e.getMessage());
            }
        }
    }

    /**
     * 查询key的生命周期
     *
     * @param key
     * @return
     */
    public static long getKeyExpire(String key) {
        Jedis jedis = getJedis();
        return jedis.ttl(key);
    }

    /**
     * 使用redis模糊清除缓存
     */
    public synchronized static void fuzzyDeletion(String key) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            // 模糊匹配所有以keyword:开头的所有key值
            Set<String> keys = jedis.keys(key + "*");
            for (String k : keys) {
                jedis.del(k);
            }
        } catch (Exception e) {
            LOGGER.error("key=" + key);
            LOGGER.error("Remove keyex error : " + e);
        } finally {
            closeRedis(jedis);
        }

    }

    /**
     * 请求获取redis锁
     * @param key
     * @param seconds
     * @return
     */
    public synchronized static boolean getLock(String key,int seconds){
        // 1.判断key数据是否存在
        if(RedisUtil.exists(key)){
            // 2.存在返回false
            return false;
        }else{
            // 3.不存在返回成功并将key数据加入缓存
            RedisUtil.set(key,"lock",seconds);
            return true;
        }
    }
}
